package com.iplant.base.utils.sql.orm;

import com.iplant.base.po.BasePO;
import com.iplant.base.po.OutResult;
import com.iplant.base.po.enums.DBCutTableModes;
import com.iplant.base.po.enums.DBEnumType;
import com.iplant.base.po.enums.ExceptionTypes;
import com.iplant.base.utils.annotation.condition.DBCondition;
import com.iplant.base.utils.annotation.condition.DBConditionValue;
import com.iplant.base.utils.annotation.dao.DBBaseDAO;
import com.iplant.base.utils.annotation.field.DBField;
import com.iplant.base.utils.annotation.field.DBFieldValue;
import com.iplant.base.utils.annotation.join.*;
import com.iplant.base.utils.annotation.join.multi.DBJoinMulti;
import com.iplant.base.utils.annotation.join.multi.select.DBJoinMultiSelect;
import com.iplant.base.utils.annotation.join.multi.select.DBJoinMultiSelectValue;
import com.iplant.base.utils.annotation.join.multi.DBJoinMultiValue;
import com.iplant.base.utils.annotation.po.DBBasePO;
import com.iplant.base.utils.general.CalendarTool;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.base.utils.sql.BaseDAO;
import com.iplant.base.utils.sql.ShrisJdbcTemplate;
import org.slf4j.LoggerFactory;

import javax.swing.text.StyledEditorKit;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xiuto
 */
public class POUtils {


    private static org.slf4j.Logger logger = LoggerFactory.getLogger(POUtils.class);

    private static POUtils _Instance = new POUtils();

    public static POUtils GetInstance() {
        return _Instance;
    }


    /**
     * BaseDAO的getInstance调用
     *
     * @param wClazz
     */
    public BaseDAO InitDao(Class<? extends BaseDAO> wClazz) {
        try {
            Method getInstance = wClazz.getMethod("getInstance");

            if (getInstance == null)
                return null;
            Object wResult = getInstance.invoke(null);

            if (wClazz.isInstance(wResult)) {
                return (BaseDAO) wResult;
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }

    /**
     * 获取实体类上DBBaseDAO注解实例
     *
     * @param clazz 实体类 class  如xx.class
     * @param <T>   实体类对象类型 必须继承于BaseDAO
     * @return DBBasePO注解实例
     */
    public <T> DBBaseDAO getDBBaseDAO(Class<T> clazz) {

        if (clazz != null && clazz.isAnnotationPresent(DBBaseDAO.class)) {
            return clazz.getAnnotation(DBBaseDAO.class);
        } else {
            return null;
        }
    }

    public <T> Class<? extends BasePO> getDBBaseDAOClass(Class<T> clazz) {

        DBBaseDAO wDBBaseDAO = getDBBaseDAO(clazz);

        if (wDBBaseDAO == null)
            return null;

        return wDBBaseDAO.value();
    }


    /**
     * 获取实体类上DBBasePO注解实例
     *
     * @param clazz 实体类class  如xx.class
     * @param <T>   实体类对象类型 必须继承于BasePO
     * @return DBBasePO注解实例
     */
    public <T> DBBasePO getDBBasePO(Class<T> clazz) {

        if (clazz != null && clazz.isAnnotationPresent(DBBasePO.class)) {
            return clazz.getAnnotation(DBBasePO.class);
        } else {
            return null;
        }
    }


    /**
     * 获取存在DBField注解的字段且exist=true的字段属性数据
     *
     * @param clazz      实体类class  如xx.class
     * @param <T>实体类对象类型 必须继承于BasePO
     * @return 字段属性数据列表
     */
    public <T> List<DBFieldValue> getDBField(String wTableAsName, Class<T> clazz, DBBasePO wDBBasePO) {

        return getDBField(wTableAsName, clazz, wDBBasePO, false);
    }

    /**
     * 获取存在DBField注解的字段的字段属性数据 并根据wIsExist 排除
     *
     * @param wT       实体类实例
     * @param wIsExist true是全包含 fasle 只获取DBField中exist=true的
     * @param <T>      实体类对象类型 必须继承于BasePO
     * @return 字段属性数据列表
     */
    public <T> List<DBFieldValue> getDBField(String wTableAsName, T wT, DBBasePO wDBBasePO, boolean wIsExist) {
        List<DBFieldValue> wResult = new ArrayList<>();

        DBFieldValue wDBFieldValue;

        List<String> wMainTableFieldName = GetMainTableFieldName(wT.getClass());

        for (Field field : wT.getClass().getFields()) {
            wDBFieldValue = getDBFieldValue(wTableAsName, field, wIsExist);
            if (wDBFieldValue == null) {
                continue;
            }
            if (!field.getDeclaringClass().equals(wT.getClass())) {
                if (wDBFieldValue.viewName.equals("Name") && !wDBBasePO.Name()) {
                    continue;
                }
                if (wDBFieldValue.viewName.equals("Code") && !wDBBasePO.Code()) {
                    continue;
                }
                if (wDBFieldValue.viewName.equals("Active") && !wDBBasePO.Active()) {
                    continue;
                }
                /**
                 * 本数据结构中存在则跳出  即重复字段跳出
                 */
                if (wMainTableFieldName.contains(field.getName()))
                    continue;
            }
            try {
                wDBFieldValue.value = field.get(wT);

            } catch (Exception ex) {
                logger.error("getDBField", ex);
            }

            wResult.add(wDBFieldValue);
        }
        return wResult;
    }

    /**
     * 获取存在DBField注解的字段的字段属性数据 并根据wIsExist 排除
     *
     * @param clazz    实体类class  如xx.class
     * @param wIsExist true是全包含 fasle 只获取DBField中exist=true的
     * @param <T>      实体类对象类型 必须继承于BasePO
     * @return 字段属性数据列表
     */
    public <T> List<DBFieldValue> getDBField(
            String wTableAsName, Class<T> clazz, DBBasePO wDBBasePO, boolean wIsExist) {
        List<DBFieldValue> wResult = new ArrayList<>();

        DBFieldValue wDBFieldValue;

        List<String> wMainTableFieldName = GetMainTableFieldName(clazz);

        for (Field field : clazz.getFields()) {

            wDBFieldValue = getDBFieldValue(wTableAsName, field, wIsExist);
            if (wDBFieldValue == null) {
                continue;
            }
            if (!field.getDeclaringClass().equals(clazz)) {
                if (wDBFieldValue.viewName.equals("Name") && !wDBBasePO.Name()) {
                    continue;
                }
                if (wDBFieldValue.viewName.equals("Code") && !wDBBasePO.Code()) {
                    continue;
                }
                if (wDBFieldValue.viewName.equals("Active") && !wDBBasePO.Active()) {
                    continue;
                }
                if (wMainTableFieldName.contains(field.getName()))
                    continue;
            }

            wResult.add(wDBFieldValue);
        }
        return wResult;
    }

    public <T> List<String> GetMainTableFieldName(Class<T> clazz) {
        List<String> wResult = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()) {
            if (Modifier.isPublic(field.getModifiers()))
                wResult.add(field.getName());
        }
        return wResult;
    }


    /**
     * 根据反射的字段属性获取对应的DBField注解实例
     *
     * @param field 字段属性
     * @return DBField注解实例
     */
    public DBField getDBField(Field field) {

        if (field.isAnnotationPresent(DBField.class)) {
            return field.getAnnotation(DBField.class);
        } else {
            return null;
        }
    }

    /**
     * 根据反射的字段属性获取对应的DBField注解实例
     *
     * @param field 字段属性
     * @return DBField注解实例
     */
    public DBFieldValue getDBFieldValue(String wTableAsName, Field field, boolean wIsExist) {

        DBField wDBField = getDBField(field);
        if (wDBField == null) return null;
        if (wIsExist && wDBField.exist()) {

            return new DBFieldValue(wTableAsName, wDBField, field);
        }
        return null;
    }


    /**
     * 根据反射的字段属性获取对应的DBJoin注解实例
     *
     * @param field 字段属性
     * @return DBField注解实例
     */
    public DBJoin getDBJoin(Field field) {

        if (field.isAnnotationPresent(DBJoin.class)) {
            return field.getAnnotation(DBJoin.class);
        } else {
            return null;
        }
    }

    /**
     * 根据反射的字段属性获取对应的DBJoin注解实例对应的值
     *
     * @param field 字段属性
     * @return DBJoin.DBJoinValue 注解实例值
     */
    public DBJoinValue getDBJoinValue(Field field, String wMainTableAsName) {
        DBJoin wDBJoin = getDBJoin(field);
        if (wDBJoin == null) return null;

        return new DBJoinValue(wDBJoin, field, wMainTableAsName);
    }


    public <T> List<DBJoinValue> getDBJoin(Class<T> clazz, DBBasePO wDBBasePO) {
        List<DBJoinValue> wResult = new ArrayList<>();

        DBJoinValue wDBJoinValue;

        List<String> wMainTableFieldName = GetMainTableFieldName(clazz);

        for (Field field : clazz.getFields()) {
            wDBJoinValue = getDBJoinValue(field, wDBBasePO.TableAsName());
            if (wDBJoinValue == null) {
                continue;
            }

            if (!field.getDeclaringClass().equals(clazz)) {
                if (wDBJoinValue.viewName.equals("Name") && !wDBBasePO.Name()) {
                    continue;
                }
                if (wDBJoinValue.viewName.equals("Code") && !wDBBasePO.Code()) {
                    continue;
                }
                if (wDBJoinValue.viewName.equals("Active") && !wDBBasePO.Active()) {
                    continue;
                }
                if (wMainTableFieldName.contains(field.getName()))
                    continue;
            }

            wResult.add(wDBJoinValue);
        }
        return wResult;
    }


    /**
     * 根据反射的字段属性获取对应的DBJoinMulti注解实例
     *
     * @param field 字段属性
     * @return DBField注解实例
     */
    public DBJoinMulti getDBJoinMulti(Field field) {

        if (field.isAnnotationPresent(DBJoinMulti.class)) {
            return field.getAnnotation(DBJoinMulti.class);
        } else {
            return null;
        }
    }

    public <T> List<DBJoinMulti> getDBJoinMultiList(Class<T> clazz) {
        List<DBJoinMulti> wResult = new ArrayList<>();

        DBJoinMulti wDBJoinMulti;
        for (Field field : clazz.getFields()) {
            wDBJoinMulti = getDBJoinMulti(field);
            if (wDBJoinMulti == null) {
                continue;
            }
            wResult.add(wDBJoinMulti);
        }
        return wResult;
    }

    public DBJoinMultiSelect getDBJoinMultiSelect(Field field) {

        if (field.isAnnotationPresent(DBJoinMultiSelect.class)) {
            return field.getAnnotation(DBJoinMultiSelect.class);
        } else {
            return null;
        }
    }


    public <T> List<DBJoinMultiSelect> getDBJoinMultiSelectList(Class<T> clazz) {
        List<DBJoinMultiSelect> wResult = new ArrayList<>();

        DBJoinMultiSelect wDBJoinMultiSelect;
        for (Field field : clazz.getFields()) {
            wDBJoinMultiSelect = getDBJoinMultiSelect(field);
            if (wDBJoinMultiSelect == null) {
                continue;
            }
            wResult.add(wDBJoinMultiSelect);
        }
        return wResult;
    }

    public <T> List<DBJoinMultiSelectValue> getDBJoinMultiSelectValueList(Class<T> clazz) throws NoSuchFieldException {
        List<DBJoinMultiSelectValue> wResult = new ArrayList<>();


        Map<String, Field> wFieldMap = GetFieldMap(clazz);

        if (wFieldMap.size() == 0)
            return wResult;

        DBJoinMultiSelect wDBJoinMultiSelect;

        for (Field field : wFieldMap.values()) {
            wDBJoinMultiSelect = getDBJoinMultiSelect(field);
            if (wDBJoinMultiSelect == null) {
                continue;
            }
            if (!wFieldMap.containsKey(wDBJoinMultiSelect.MainTableField()))
                continue;

            wResult.add(new DBJoinMultiSelectValue(wDBJoinMultiSelect,
                    field, wDBJoinMultiSelect.ItemClazz().getField(wDBJoinMultiSelect.OutTableField()),
                    wFieldMap.get(wDBJoinMultiSelect.MainTableField())));
        }
        return wResult;
    }


    public <T> Map<String, Field> GetFieldMap(Class<T> clazz) {
        Map<String, Field> wResult = new HashMap<>();

        for (Field field : clazz.getFields()) {

            if (wResult.containsKey(field.getName())) {
                if (!field.getDeclaringClass().equals(clazz))
                    continue;
            }
            wResult.put(field.getName(), field);
        }
        return wResult;
    }

    public <T> List<DBJoinMultiValue> getDBJoinMultiValueList(Class<T> clazz) {
        List<DBJoinMultiValue> wResult = new ArrayList<>();


        Map<String, Field> wFieldMap = GetFieldMap(clazz);

        if (wFieldMap.size() == 0)
            return wResult;

        DBJoinMulti wDBJoinMulti;

        for (Field field : wFieldMap.values()) {

            wDBJoinMulti = getDBJoinMulti(field);
            if (wDBJoinMulti == null) {
                continue;
            }
            if (!wFieldMap.containsKey(wDBJoinMulti.MainTableField()))
                continue;

            wResult.add(new DBJoinMultiValue(wDBJoinMulti, field, wFieldMap.get(wDBJoinMulti.MainTableField())));
        }
        return wResult;
    }


    /**
     * 根据反射的字段属性获取对应的DBCondition注解实例
     *
     * @param field 字段属性
     * @return DBCondition注解实例
     */
    public DBCondition getDBCondition(Field field) {

        if (field.isAnnotationPresent(DBCondition.class)) {
            return field.getAnnotation(DBCondition.class);
        } else {
            return null;
        }
    }


    /**
     * 根据反射的字段属性获取对应的DBCondition注解实例值
     *
     * @param field 字段属性
     * @return DBCondition 注解实例值
     */
    public DBConditionValue getDBConditionValue(Field field) {
        DBCondition wDBCondition = getDBCondition(field);
        if (wDBCondition == null) return null;

        return new DBConditionValue(wDBCondition, field);
    }

    public <T> List<DBConditionValue> getDBCondition(Class<T> clazz, DBBasePO wDBBasePO) {
        List<DBConditionValue> wResult = new ArrayList<>();

        DBConditionValue wDBConditionValue;
        DBField wDBField;
        List<String> wMainTableFieldName = GetMainTableFieldName(clazz);

        for (Field field : clazz.getFields()) {
            wDBField = getDBField(field);
            if (wDBField != null && !wDBField.exist()) continue;
            wDBConditionValue = getDBConditionValue(field);

            if (wDBConditionValue == null) {
                continue;
            }
            if (!field.getDeclaringClass().equals(clazz)) {
                if (wDBConditionValue.viewName.equals("Name") && !wDBBasePO.Name()) {
                    continue;
                }
                if (wDBConditionValue.viewName.equals("Code") && !wDBBasePO.Code()) {
                    continue;
                }
                if (wDBConditionValue.viewName.equals("Active") && !wDBBasePO.Active()) {
                    continue;
                }
                if (wMainTableFieldName.contains(field.getName()))
                    continue;
            }


            wResult.add(wDBConditionValue);
        }
        return wResult;
    }


    /**
     * 创建查询条件语句 where后语句
     *
     * @param wClazz                实体类类型
     * @param wDBConditionValueList 条件列表
     * @param wParams               查询条件数据
     * @param wErrorCode            错误码
     * @return
     */
    public List<String> CreateConditionStringList(
            Class<?> wClazz, List<DBConditionValue> wDBConditionValueList, Map<String, Object> wParams,
            OutResult<Integer> wErrorCode) {
        /**
         * 查询条件集合
         */
        List<String> wConditionList = new ArrayList<>();
        //组装where条件字段
        boolean wCheckResult = true;
        for (DBConditionValue wDBConditionValue : wDBConditionValueList) {

            if (!wDBConditionValue.Exist) {

                logger.info(StringUtils.Format("Class:{0} Field:{1} 注解DBCondition时需要字段存在DBJoin或DBField的注解",
                        wClazz.getName(), wDBConditionValue.viewName));
                continue;
                // wErrorCode.Result = ExceptionTypes.Exception.getValue();
                //return wConditionList;
            }
            wCheckResult = wDBConditionValue.CheckValue(wParams, wErrorCode);

            if (wErrorCode.Result != 0) {
                return wConditionList;
            }
            if (!wCheckResult)
                continue;
            wConditionList.add(wDBConditionValue.ToString(
                    wParams.containsKey(wDBConditionValue.ParamName) ? wParams.get(wDBConditionValue.ParamName) : null,
                    wParams.containsKey(wDBConditionValue.ParamName2) ? wParams.get(wDBConditionValue.ParamName2) :
                            null));

        }
        return wConditionList;
    }


    /**
     * 获取关联表列表
     * 并对查询条件字段填充 ，对条件配置填充
     *
     * @param wDBJoinValueList      关联字段列表
     * @param wSelectFieldList
     * @param wDBConditionValueList
     * @return
     */
    public Map<String, DBJoinValue> GetDBJoinValueMap(
            List<DBJoinValue> wDBJoinValueList, List<String> wSelectFieldList,
            List<DBConditionValue> wDBConditionValueList) {
        Map<String, DBJoinValue> wTableJoinList = new HashMap<>();
        //将wDBJoinValueList变更为 tx.xx as xx 若相同 去除 as  并生成   join xx.xx  as xx on condition
        //将注解数据取出， 有些给了 有些没给  将没给的用给了的进行赋值
        for (DBJoinValue wDBJoinValue : wDBJoinValueList) {
            //相同表别名进行条件合并
            if (wTableJoinList.containsKey(wDBJoinValue.tableAsName)) {
                //JoinIndex 取配置最大值
                if (wDBJoinValue.JoinIndex > wTableJoinList.get(wDBJoinValue.tableAsName).JoinIndex) {
                    wTableJoinList.get(wDBJoinValue.tableAsName).JoinIndex = wDBJoinValue.JoinIndex;
                }
                //如果表名为空并且已存在表名则自动复制  tableName取第一个且不为空配置
                if (StringUtils.isNotEmpty(wDBJoinValue.tableName) && StringUtils.isEmpty(
                        wTableJoinList.get(wDBJoinValue.tableAsName).tableName)) {
                    wTableJoinList.get(wDBJoinValue.tableAsName).tableName = wDBJoinValue.tableName;
                }
                //取除了left的最后一个不同配置
                if (wDBJoinValue.JoinMode != DBJoin.DBJoinMode.Left) {
                    wTableJoinList.get(wDBJoinValue.tableAsName).JoinMode = wDBJoinValue.JoinMode;
                }
                //条件全部获取
                if (wDBJoinValue.ConditionalJoin != null && wDBJoinValue.ConditionalJoin.size() > 0) {
                    for (String wConditionalJoin : wDBJoinValue.ConditionalJoin) {

                        if (wTableJoinList.get(wDBJoinValue.tableAsName).ConditionalJoin.contains(wConditionalJoin))
                            continue;
                        ;
                        wTableJoinList.get(wDBJoinValue.tableAsName).ConditionalJoin.add(wConditionalJoin);
                    }

                }
            } else {
                wTableJoinList.put(wDBJoinValue.tableAsName, wDBJoinValue.Clone());
            }
            //将关联表字段添加到查询字段中 并根据设置 生成查询字段sql  如 t1.Name、t1.ID as TID 等
            wSelectFieldList.add(wDBJoinValue.CreateSelectField());

            wDBJoinValue.SetDBConditionValueConfig(wDBConditionValueList);
        }
        return wTableJoinList;
    }

    public List<String> CreateTable(
            DBBasePO wDBBasePO, List<DBFieldValue> wDBFieldValueList) {
        return CreateTable(wDBBasePO.DBType(), wDBBasePO.Schemas().getDBName(), wDBBasePO.TableName(),
                wDBFieldValueList, wDBBasePO.IndexCol(), wDBBasePO.Comment());
    }

    public List<String> CreateTable(
            DBEnumType wSQLType, String wDB_Name, String wCurrentTableName, List<DBFieldValue> wDBFieldValueList,
            String[] IndexCols, String wComment) {
        List<String> wResult = new ArrayList<>();
        switch (wSQLType) {
            case SQLServer:
                wResult = CreateSqlServerTable(wDB_Name, wCurrentTableName, wDBFieldValueList, IndexCols);
                break;
            case Oracle:
                break;
            case Access:
                break;
            case Default:
            case MySQL:
            default:
                wResult = CreateMysqlTable(wDB_Name, wCurrentTableName, wDBFieldValueList, IndexCols, wComment);
                break;

        }
        return wResult;
    }


    public String GetDeleteTableName(String wTableName) {
        return wTableName + "_delete";
    }

    public <T extends BasePO> void CreateTable(Class<T> wClazz, DBBasePO wDBBasePO, ShrisJdbcTemplate wDBPool) {
        this.CreateTable(wClazz, wDBBasePO, wDBPool, false);
    }

    public <T extends BasePO> void CreateTable(Class<T> wClazz, DBBasePO wDBBasePO, ShrisJdbcTemplate wDBPool,
                                               boolean wHasDelete) {
        List<DBFieldValue> wDBFieldValueList = this.getDBField(wDBBasePO.TableAsName(), wClazz,
                wDBBasePO, true);
        if (wDBFieldValueList == null || wDBFieldValueList.size() == 0) {
            return;
        }

        String wCurrentName = this.GetTableName(wDBBasePO.CutTableMode(), Calendar.getInstance(),
                wDBBasePO.TableName());

        List<String> wSqlList = new ArrayList<>();

        if (wDBBasePO.CutTableMode() == DBCutTableModes.Default) {
            if (wHasDelete) {
                wSqlList.addAll(this.CreateTable(wDBBasePO.DBType(), wDBBasePO.Schemas().getDBName(),
                        GetDeleteTableName(wDBBasePO.TableName()), wDBFieldValueList, wDBBasePO.IndexCol(),
                        wDBBasePO.Comment() + "删除记录表"));
            }
            wSqlList.addAll(this.CreateTable(wDBBasePO.DBType(), wDBBasePO.Schemas().getDBName(),
                    wCurrentName, wDBFieldValueList, wDBBasePO.IndexCol(), wDBBasePO.Comment()));

            wDBPool.Execute(wSqlList);
        } else {

            //表是否存在
            List<String> wTableNames = this.GetCutTableName(wDBBasePO.Schemas().getDBName(),
                    wDBBasePO.TableName(), wDBBasePO.DBType(), wDBPool);

            if (wTableNames.contains(wCurrentName))
                return;

            if (wHasDelete) {
                wSqlList.addAll(this.CreateTable(wDBBasePO.DBType(), wDBBasePO.Schemas().getDBName(),
                        GetDeleteTableName(wDBBasePO.TableName()), wDBFieldValueList, wDBBasePO.IndexCol(),
                        wDBBasePO.Comment() + "删除记录表"));
            }

            //不存在创表
            wSqlList.addAll(this.CreateTable(wDBBasePO.DBType(), wDBBasePO.Schemas().getDBName(),
                    wCurrentName, wDBFieldValueList, wDBBasePO.IndexCol(), wDBBasePO.Comment()));

            wDBPool.Execute(wSqlList);

            if (wTableNames.size() == 0) {
                return;
            }
            //有历史表迁移自增数据
            this.SetAUTO_INCREMENT(wDBBasePO, wTableNames.get(0), wDBPool);

        }
    }


    private int GetAUTO_INCREMENT(String wTableName, DBBasePO wDBBasePO, ShrisJdbcTemplate wDBPool) {

        String wSql = "";

        switch (wDBBasePO.DBType()) {


            case SQLServer:
                wSql = StringUtils.Format(" use [{0}]; SELECT IDENT_CURRENT(''{1}'') AS AUTO_INCREMENT ; ",
                        wDBBasePO.Schemas().getDBName(), wTableName);
                break;
            case Oracle:
                break;
            case Access:
                break;
            case MySQL:
            case Default:
            default:
                wSql = StringUtils.Format("SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES " +
                                "  WHERE TABLE_SCHEMA = ''{0}'' AND TABLE_NAME = ''{1}'' ;",
                        wDBBasePO.Schemas().getDBName(), wTableName);

                break;
        }

        if (StringUtils.isEmpty(wSql))
            return 0;

        Map<String, Object> wResult = wDBPool.queryForMap(wSql, new HashMap<>());

        return StringUtils.parseInt(wResult.get("AUTO_INCREMENT"));
    }

    private void SetAUTO_INCREMENT(int wCurrent, DBBasePO wDBBasePO, ShrisJdbcTemplate wDBPool) {

        String wSql = "";

        switch (wDBBasePO.DBType()) {


            case SQLServer:

                wSql = StringUtils.Format(" use [{0}]; DBCC CHECKIDENT (''{1}'', RESEED, {2});",
                        wDBBasePO.Schemas().getDBName(), this.GetTableName(wDBBasePO.CutTableMode(),
                                Calendar.getInstance(), wDBBasePO.TableName()), wCurrent);

                break;
            case Oracle:
                break;
            case Access:
                break;
            case MySQL:
            case Default:
            default:
                wSql = StringUtils.Format("ALTER TABLE {0}.{1} AUTO_INCREMENT = {2} ;",
                        wDBBasePO.Schemas().getDBName(), this.GetTableName(wDBBasePO.CutTableMode(),
                                Calendar.getInstance(), wDBBasePO.TableName()), wCurrent);

                break;
        }

        if (StringUtils.isEmpty(wSql))
            return;


        wDBPool.update(wSql, new HashMap<>());
    }


    private void SetAUTO_INCREMENT(DBBasePO wDBBasePO, String wOldTable, ShrisJdbcTemplate wDBPool) {

        int wAUTO_INCREMENT = this.GetAUTO_INCREMENT(wOldTable, wDBBasePO, wDBPool);

        if (wAUTO_INCREMENT <= 1)
            return;

        this.SetAUTO_INCREMENT(wAUTO_INCREMENT, wDBBasePO, wDBPool);
    }


    private List<String> CreateMysqlTable(
            String wDB_Name, String wCurrentTableName, List<DBFieldValue> wDBFieldValueList, String[] IndexCols,
            String wComment) {

        List<String> wSqlList = new ArrayList<>();
        wSqlList.add(StringUtils.Format(" use `{0}` ;", wDB_Name));

        List<String> wFieldSqlList = new ArrayList<>();

        wFieldSqlList.add(" `ID` int(11) NOT NULL AUTO_INCREMENT ");

        for (DBFieldValue wDBFieldValue : wDBFieldValueList) {
            if (wDBFieldValue.name.equals("ID")) {
                continue;
            }
            wFieldSqlList.add(StringUtils.Format("`{0}` {1} {2} Default {3}", wDBFieldValue.name,
                    DMLTool.GetInstance().GetMySqlType(wDBFieldValue.TypeName, wDBFieldValue.length),
                    wDBFieldValue.notNull ? "NOT NULL" : "NULL", wDBFieldValue.getDefaultValue(DBEnumType.MySQL)));
        }
        String wIndexString = "";

        if (IndexCols != null && IndexCols.length > 0) {

            for (String indexCol : IndexCols) {

                if (StringUtils.isEmpty(indexCol))
                    continue;
                wIndexString += StringUtils.Format(" , KEY `{0}` ({1}) ", indexCol.replace(",", "_"), indexCol);
            }

        }
        wSqlList.add(StringUtils.Format("  Create Table IF NOT EXISTS  `{0}` ({1} ,PRIMARY KEY (`ID`) {2} )" +
                        "  ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT=''{3}''  ",
                wCurrentTableName, StringUtils.Join(",", wFieldSqlList), wIndexString, wComment));
        //列不存在创建
        return wSqlList;
    }


    private List<String> CreateSqlServerTable(
            String wDB_Name, String wCurrentTableName, List<DBFieldValue> wDBFieldValueList, String[] IndexCols) {

        List<String> wSqlList = new ArrayList<>();
        wSqlList.add(StringUtils.Format(" use `{0}` ;", wDB_Name));

        List<String> wFieldSqlList = new ArrayList<>();

        wFieldSqlList.add(" [ID] [int] IDENTITY(1,1) NOT NULL ");

        for (DBFieldValue wDBFieldValue : wDBFieldValueList) {
            if (wDBFieldValue.name.equals("ID")) {
                continue;
            }
            wFieldSqlList.add(StringUtils.Format("[{0}] {1} {2} Default {3}", wDBFieldValue.name,
                    DMLTool.GetInstance().GetSqlServerType(wDBFieldValue.TypeName, wDBFieldValue.length),
                    wDBFieldValue.notNull ? "NOT NULL" : "NULL", wDBFieldValue.getDefaultValue(DBEnumType.SQLServer)));
        }

        String wIndexString = "";

        if (IndexCols != null && IndexCols.length > 0) {

            for (String indexCol : IndexCols) {

                if (StringUtils.isEmpty(indexCol))
                    continue;
                wIndexString += StringUtils.Format("  Index [{0}] ({1}),", indexCol.replace(",", "_"), indexCol);
            }

        }

        wSqlList.add(StringUtils.Format(" if not exists(select * from sysobjects where  type=''U'' and name=''{0}''  " +
                        ") " +
                        " Create Table  [dbo].[{0}] ({1}  {2} ,CONSTRAINT [PK_tb_{0}_{3}] PRIMARY KEY CLUSTERED ([ID]" +
                        " DESC) )" +
                        " WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS " +
                        "= ON, " +
                        " ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] ;",
                wCurrentTableName, StringUtils.Join(",", wFieldSqlList), wIndexString, new Random().nextInt(1000)));

        //列不存在就创建列

        return wSqlList;
    }


    public <T extends BasePO> Map<String, Object> GetImportParam(T wBasePO, DBBasePO dbBasePO, int wIndex,
                                                                 OutResult<Integer> wErrorCode) {

        Map<String, Object> wParams = new HashMap<>();
        List<DBFieldValue> dbFieldList = POUtils.GetInstance().getDBField(
                dbBasePO.TableAsName(), wBasePO, dbBasePO, true);


        for (DBFieldValue dbFieldValue : dbFieldList) {

            if (!dbBasePO.Code() && "Code".equals(dbFieldValue.name)) {
                continue;
            }
            if (!dbBasePO.Name() && "Name".equals(dbFieldValue.name)) {
                continue;
            }
            if (!dbBasePO.Active() && "Active".equals(dbFieldValue.name)) {
                continue;
            }

            if (dbFieldValue.Insert || dbFieldValue.Update) {
                wParams.put(dbFieldValue.name, dbFieldValue.getValue());
            }
        }


        return wParams;
    }


    public <T extends BasePO> Map<String, Object> GetUpdateParam(T wBasePO, DBBasePO dbBasePO, BaseDAO wBaseDAO,
                                                                 int wIndex, OutResult<Integer> wErrorCode) {

        Map<String, Object> wParams = new HashMap<>();
        List<DBFieldValue> dbFieldList = POUtils.GetInstance().getDBField(
                dbBasePO.TableAsName(), wBasePO, dbBasePO, true);

        boolean wIsInsert = wBasePO.ID <= 0;

        for (DBFieldValue dbFieldValue : dbFieldList) {
            if (!dbFieldValue.name.equals(dbBasePO.PrimaryKey())) {
                continue;
            }
            if (dbFieldValue.value == null) {
                break;
            }
            if (dbFieldValue.value instanceof Integer || dbFieldValue.value instanceof Long) {
                wIsInsert = StringUtils.parseLong(dbFieldValue.value) <= 0;
            } else {
                wIsInsert = StringUtils.isEmpty(dbFieldValue.value.toString());
            }
            break;
        }
        for (DBFieldValue dbFieldValue : dbFieldList) {

            if (!dbBasePO.Code() && "Code".equals(dbFieldValue.name)) {
                continue;
            }
            if (!dbBasePO.Name() && "Name".equals(dbFieldValue.name)) {
                continue;
            }
            if (!dbBasePO.Active() && "Active".equals(dbFieldValue.name)) {
                continue;
            }

            if ((wIsInsert && dbFieldValue.Insert) || (!wIsInsert && dbFieldValue.Update)) {
                if (dbFieldValue.CheckValue && !StringUtils.IsNotEmptyValue(dbFieldValue.getValue(),
                        dbFieldValue.TypeName, -1, 0)) {
                    logger.info("UpdatePo  table:{0},Field:{1} Check Value Fail!", dbBasePO.TableName(),
                            dbFieldValue.viewName);
                    wErrorCode.set(ExceptionTypes.Parameter.getValue());
                    return wParams;
                }
                wParams.put(dbFieldValue.name, dbFieldValue.getValue());
            } else if (wIsInsert && !dbFieldValue.Insert && dbFieldValue.ValueAuto) {
                wParams.put(dbFieldValue.name, wBaseDAO.CreateMaxInt(wBaseDAO.getTableName(dbBasePO), 0,
                        dbFieldValue.name
                        , 0));
            }
        }
        if (wIsInsert) {
            if (!dbBasePO.InsertEnable()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wParams;
            }
            if (dbBasePO.CodeAuto() && StringUtils.isEmpty(wBasePO.Code) && wParams.containsKey("Code")) {
                wBasePO.Code = wBaseDAO.CreateMaxCode(
                        wBaseDAO.getTableName(dbBasePO), dbBasePO.CodePrefix(), "Code", dbBasePO.CodeNum(), wBasePO,
                        wIndex);
                wParams.put("Code", wBasePO.Code);
            }
        } else {
            if (!dbBasePO.UpdateEnable()) {
                wErrorCode.set(ExceptionTypes.Parameter.getValue());
                return wParams;
            }
            if (dbBasePO.CodeAuto() && StringUtils.isEmpty(wBasePO.Code)) {
                wParams.remove("Code");
            }
        }

        return wParams;
    }


    public List<String> GetCutTableName(String wDBName, String wTableName, DBEnumType wDBType,
                                        ShrisJdbcTemplate wDBPool) {
        return GetCutTableName(wDBName, wTableName, wDBType, wDBPool, true);

    }

    public List<String> GetCutTableName(String wDBName, String wTableName, DBEnumType wDBType,
                                        ShrisJdbcTemplate wDBPool, boolean wIsReversed) {

        List<String> wResult = new ArrayList<>();

        try {
            String sql = "";
            switch (wDBType) {
                case SQLServer:
                    sql = StringUtils.Format("SELECT TABLE_NAME FROM [{0}].INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE" +
                            " = ''BASE TABLE'' AND TABLE_NAME  LIKE ''{1}%''  ;", wDBName, wTableName);
                    break;
                case Oracle:
                    break;
                case Access:
                    break;
                case Default:
                case MySQL:
                default:
                    sql = StringUtils.Format("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE  TABLE_SCHEMA  =" +
                            " ''{0}'' AND TABLE_NAME  LIKE ''{1}%''  ;", wDBName, wTableName);

                    break;

            }

            List<Map<String, Object>> wQueryResult = wDBPool.queryForList(sql, new HashMap<String, Object>());

            for (Map<String, Object> wReader : wQueryResult) {
                wResult.add(StringUtils.parseString(wReader.get("TABLE_NAME")));
            }

            if (wResult != null && wResult.size() > 0) {

                Collections.sort(wResult);

                if (wIsReversed)
                    Collections.reverse(wResult);

            }

        } catch (Exception ex) {
            logger.error("GetCutTableName DBName:{} TABLE_NAME:{} Error:{}", wDBName, wTableName, ex.getMessage());
        }
        return wResult;
    }


    public <T extends BasePO> Map<Calendar, List<T>> GroupByCreateTime(
            List<T> wBasePoList, DBCutTableModes
            wDBCutTableModes) {
        Map<Calendar, List<T>> wResult = new HashMap<Calendar, List<T>>();
        switch (wDBCutTableModes) {
            case Year:
                wResult = wBasePoList.stream().collect(Collectors.groupingBy(p -> CalendarTool.getYear(p.CreateTime)));

                break;
            case Month:
                wResult = wBasePoList.stream().collect(Collectors.groupingBy(p -> CalendarTool.getMonth(p.CreateTime)));

                break;
            case Day:
                wResult = wBasePoList.stream().collect(Collectors.groupingBy(p -> CalendarTool.getDate(p.CreateTime)));
                break;
            case Default:
                break;
            default:
                break;
        }
        return wResult;
    }


    public String GetTableName(DBCutTableModes wDBCutTableModes, Calendar wDate, String wTableName) {

        String wResult = wTableName;
        switch (wDBCutTableModes) {
            case Year:
                wResult = wResult + "_" + StringUtils.parseCalendarToString(wDate, "yyyy");

                break;
            case Month:
                wResult = wResult + "_" + StringUtils.parseCalendarToString(wDate, "yyyy_MM");
                break;
            case Day:
                wResult = wResult + "_" + StringUtils.parseCalendarToString(wDate, "yyyy_MM_dd");
                break;
            case Default:
                break;
            default:
                break;
        }

        return wResult;

    }

    public List<String> FilterTableName(DBCutTableModes wDBCutTableModes, Calendar wStartTime, Calendar wEndTime,
                                        String wTableName, List<String> wTableNames) {
        if (wStartTime == null && wEndTime == null)
            return wTableNames;


        if (wEndTime == null || wEndTime.compareTo(CalendarTool.getBasicDate()) <= 0)
            wEndTime = Calendar.getInstance();

        if (wStartTime == null || wStartTime.compareTo(CalendarTool.getBasicDate()) < 0)
            wStartTime = CalendarTool.getBasicDate();


        List<String> wResult = new ArrayList<>();
        if (StringUtils.isEmpty(wTableName) || wTableNames == null || wTableNames.size() == 0)
            return wResult;
        Calendar wDate;
        for (String tableName : wTableNames) {
            if (!tableName.startsWith(wTableName))
                continue;

            switch (wDBCutTableModes) {
                case Year:
                    wDate = StringUtils.parseCalendar(tableName.substring(wTableName.length()), "_yyyy");

                    break;
                case Month:
                    wDate = StringUtils.parseCalendar(tableName.substring(wTableName.length()), "_yyyy_MM");

                    break;
                case Day:
                    wDate = StringUtils.parseCalendar(tableName.substring(wTableName.length()), "_yyyy_MM_dd");

                    break;
                case Default:
                default:
                    continue;
            }
            if (wDate == null)
                continue;
            if (wDate.compareTo(wStartTime) >= 0 && wDate.compareTo(wEndTime) <= 0)
                wResult.add(tableName);
        }

        return wResult;

    }

}
